package com.clouddms.service.lifecycle;

import com.clouddms.entity.FileInfo;
import com.clouddms.repository.FileRepository;
import com.clouddms.service.common.IService;
import com.clouddms.service.common.ServiceStatus;
import com.clouddms.service.storage.BackupService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDateTime;
import java.util.List;

/**
 * 文件生命周期管理服务
 * 负责文件的定时清理、归档和生命周期管理
 */
@Service
public class LifecycleService implements IService {

    private static final Logger logger = LoggerFactory.getLogger(LifecycleService.class);

    @Autowired
    private FileRepository fileRepository;

    @Autowired
    private BackupService backupService;

    @Value("${clouddms.lifecycle.cleanup.enabled:true}")
    private boolean cleanupEnabled;

    @Value("${clouddms.lifecycle.cleanup.deleted-file-retention-days:7}")
    private int deletedFileRetentionDays;

    @Value("${clouddms.lifecycle.cleanup.orphan-file-check:true}")
    private boolean orphanFileCheckEnabled;

    @Value("${clouddms.lifecycle.archive.enabled:false}")
    private boolean archiveEnabled;

    @Value("${clouddms.lifecycle.archive.days-threshold:365}")
    private int archiveDaysThreshold;

    @Value("${clouddms.lifecycle.archive.path:archives}")
    private String archivePath;

    /**
     * 定时清理已删除的文件
     * 每天凌晨3点执行
     */
    @Scheduled(cron = "${clouddms.lifecycle.cleanup.schedule:0 0 3 * * ?}")
    @Transactional
    public void cleanupDeletedFiles() {
        if (!cleanupEnabled) {
            logger.debug("文件清理已禁用，跳过清理任务");
            return;
        }

        try {
            logger.info("开始清理已删除的文件，保留天数: {}", deletedFileRetentionDays);

            LocalDateTime cutoffTime = LocalDateTime.now().minusDays(deletedFileRetentionDays);
            List<FileInfo> filesToCleanup = fileRepository.findFilesToCleanup(cutoffTime);

            int cleanedCount = 0;
            long totalSizeFreed = 0L;

            for (FileInfo fileInfo : filesToCleanup) {
                try {
                    CleanupResult result = permanentDeleteFile(fileInfo);
                    if (result.isSuccess()) {
                        cleanedCount++;
                        totalSizeFreed += result.getSizeFreed();
                        logger.debug("已清理文件: {} ({})", fileInfo.getOriginalFilename(), 
                                formatFileSize(result.getSizeFreed()));
                    }
                } catch (Exception e) {
                    logger.warn("清理文件失败: fileId={}, error={}", fileInfo.getFileId(), e.getMessage());
                }
            }

            logger.info("文件清理完成，清理数量: {}, 释放空间: {}", 
                    cleanedCount, formatFileSize(totalSizeFreed));

        } catch (Exception e) {
            logger.error("执行文件清理任务时发生错误", e);
        }
    }

    /**
     * 定时检查和清理孤儿文件
     * 每周日凌晨4点执行
     */
    @Scheduled(cron = "${clouddms.lifecycle.orphan-check.schedule:0 0 4 * * SUN}")
    public void cleanupOrphanFiles() {
        if (!cleanupEnabled || !orphanFileCheckEnabled) {
            logger.debug("孤儿文件检查已禁用，跳过清理任务");
            return;
        }

        try {
            logger.info("开始检查和清理孤儿文件");

            OrphanCleanupResult result = findAndCleanupOrphanFiles();
            
            logger.info("孤儿文件清理完成，检查文件数: {}, 清理数量: {}, 释放空间: {}", 
                    result.getCheckedCount(), result.getCleanedCount(), 
                    formatFileSize(result.getSizeFreed()));

        } catch (Exception e) {
            logger.error("执行孤儿文件清理任务时发生错误", e);
        }
    }

    /**
     * 定时归档长期未访问的文件
     * 每月第一天凌晨5点执行
     */
    @Scheduled(cron = "${clouddms.lifecycle.archive.schedule:0 0 5 1 * ?}")
    @Transactional
    public void archiveOldFiles() {
        if (!archiveEnabled) {
            logger.debug("文件归档已禁用，跳过归档任务");
            return;
        }

        try {
            logger.info("开始归档长期未访问的文件，阈值天数: {}", archiveDaysThreshold);

            LocalDateTime archiveThreshold = LocalDateTime.now().minusDays(archiveDaysThreshold);
            List<FileInfo> filesToArchive = findFilesForArchive(archiveThreshold);

            int archivedCount = 0;
            long totalSizeArchived = 0L;

            for (FileInfo fileInfo : filesToArchive) {
                try {
                    ArchiveResult result = archiveFile(fileInfo);
                    if (result.isSuccess()) {
                        archivedCount++;
                        totalSizeArchived += fileInfo.getFileSize();
                        logger.debug("已归档文件: {} ({})", fileInfo.getOriginalFilename(), 
                                formatFileSize(fileInfo.getFileSize()));
                    }
                } catch (Exception e) {
                    logger.warn("归档文件失败: fileId={}, error={}", fileInfo.getFileId(), e.getMessage());
                }
            }

            logger.info("文件归档完成，归档数量: {}, 归档大小: {}", 
                    archivedCount, formatFileSize(totalSizeArchived));

        } catch (Exception e) {
            logger.error("执行文件归档任务时发生错误", e);
        }
    }

    /**
     * 永久删除文件
     * @param fileInfo 文件信息
     * @return 清理结果
     */
    private CleanupResult permanentDeleteFile(FileInfo fileInfo) {
        try {
            long sizeFreed = 0L;

            // 删除物理文件
            Path filePath = Paths.get(fileInfo.getFilePath());
            if (Files.exists(filePath)) {
                sizeFreed = Files.size(filePath);
                Files.delete(filePath);
                logger.debug("物理文件已删除: {}", fileInfo.getFilePath());
            }

            // 删除数据库记录
            fileRepository.delete(fileInfo);

            return CleanupResult.success(sizeFreed);

        } catch (Exception e) {
            logger.error("永久删除文件失败: fileId={}", fileInfo.getFileId(), e);
            return CleanupResult.failure(e.getMessage());
        }
    }

    /**
     * 查找并清理孤儿文件
     * @return 清理结果
     */
    private OrphanCleanupResult findAndCleanupOrphanFiles() {
        // TODO: 实现孤儿文件检查逻辑
        // 1. 遍历存储目录中的所有文件
        // 2. 检查每个文件是否在数据库中有对应记录
        // 3. 删除没有数据库记录的孤儿文件
        
        logger.info("孤儿文件检查功能暂未实现");
        return new OrphanCleanupResult(0, 0, 0L);
    }

    /**
     * 查找需要归档的文件
     * @param threshold 时间阈值
     * @return 需要归档的文件列表
     */
    private List<FileInfo> findFilesForArchive(LocalDateTime threshold) {
        // 查找长期未访问的大文件
        return fileRepository.findLargeFilesByUserId(null, 1024 * 1024 * 100L); // 100MB以上的文件
    }

    /**
     * 归档文件
     * @param fileInfo 文件信息
     * @return 归档结果
     */
    private ArchiveResult archiveFile(FileInfo fileInfo) {
        try {
            // 1. 创建备份
            BackupService.BackupResult backupResult = backupService.createBackup(
                    fileInfo.getFileId(), "ARCHIVE");
            
            if (!backupResult.isSuccess()) {
                return ArchiveResult.failure("创建归档备份失败: " + backupResult.getMessage());
            }

            // 2. 移动文件到归档目录
            Path originalPath = Paths.get(fileInfo.getFilePath());
            Path archiveFilePath = generateArchivePath(fileInfo);
            
            createDirectoriesIfNotExists(archiveFilePath.getParent());
            Files.move(originalPath, archiveFilePath);

            // 3. 更新文件记录
            fileInfo.setFilePath(archiveFilePath.toString());
            fileRepository.save(fileInfo);

            logger.info("文件已归档: fileId={}, archivePath={}", 
                    fileInfo.getFileId(), archiveFilePath);

            return ArchiveResult.success(archiveFilePath.toString());

        } catch (Exception e) {
            logger.error("归档文件失败: fileId={}", fileInfo.getFileId(), e);
            return ArchiveResult.failure(e.getMessage());
        }
    }

    /**
     * 生成归档路径
     */
    private Path generateArchivePath(FileInfo fileInfo) {
        return Paths.get(archivePath, 
                "user_" + fileInfo.getUserId(),
                String.valueOf(fileInfo.getCreatedAt().getYear()),
                String.valueOf(fileInfo.getCreatedAt().getMonthValue()),
                fileInfo.getStoredFilename());
    }

    /**
     * 创建目录（如果不存在）
     */
    private void createDirectoriesIfNotExists(Path dirPath) throws IOException {
        if (!Files.exists(dirPath)) {
            Files.createDirectories(dirPath);
        }
    }

    /**
     * 格式化文件大小
     */
    private String formatFileSize(long size) {
        if (size == 0) return "0 B";
        
        String[] units = {"B", "KB", "MB", "GB", "TB"};
        int unitIndex = 0;
        double sizeDouble = size;
        
        while (sizeDouble >= 1024 && unitIndex < units.length - 1) {
            sizeDouble /= 1024;
            unitIndex++;
        }
        
        return String.format("%.2f %s", sizeDouble, units[unitIndex]);
    }

    /**
     * 获取生命周期管理统计信息
     * @return 统计信息
     */
    public LifecycleStats getLifecycleStats() {
        try {
            LocalDateTime cutoffTime = LocalDateTime.now().minusDays(deletedFileRetentionDays);
            List<FileInfo> pendingCleanup = fileRepository.findFilesToCleanup(cutoffTime);
            
            long pendingCleanupSize = pendingCleanup.stream()
                    .mapToLong(FileInfo::getFileSize)
                    .sum();

            return new LifecycleStats(
                    pendingCleanup.size(),
                    pendingCleanupSize,
                    cleanupEnabled,
                    archiveEnabled
            );
        } catch (Exception e) {
            logger.error("获取生命周期统计信息失败", e);
            return new LifecycleStats(0, 0L, false, false);
        }
    }

    // IService 接口实现
    @Override
    public String getServiceName() {
        return "lifecycle-service";
    }

    @Override
    public String getDisplayName() {
        return "生命周期管理服务";
    }

    @Override
    public String getDescription() {
        return "负责文件的定时清理、归档和生命周期管理";
    }

    @Override
    public ServiceStatus getStatus() {
        if (!cleanupEnabled) {
            return ServiceStatus.DISABLED;
        }
        
        try {
            // 检查数据库连接
            fileRepository.count();
            return ServiceStatus.RUNNING;
        } catch (Exception e) {
            logger.error("生命周期服务状态检查失败: {}", e.getMessage());
            return ServiceStatus.DISABLED;
        }
    }

    @Override
    public HealthStatus getHealthStatus() {
        try {
            if (!cleanupEnabled) {
                return new HealthStatus(true, "生命周期管理已禁用");
            }

            LifecycleStats stats = getLifecycleStats();
            
            return new HealthStatus(true, 
                    String.format("服务正常运行，待清理文件: %d 个，大小: %s", 
                            stats.getPendingCleanupCount(), 
                            formatFileSize(stats.getPendingCleanupSize())));
        } catch (Exception e) {
            return new HealthStatus(false, "健康检查失败: " + e.getMessage());
        }
    }

    @Override
    public int getPriority() {
        return 4; // 较低优先级
    }

    @Override
    public String getVersion() {
        return "1.0.0";
    }

    /**
     * 清理结果类
     */
    public static class CleanupResult {
        private final boolean success;
        private final String message;
        private final long sizeFreed;

        private CleanupResult(boolean success, String message, long sizeFreed) {
            this.success = success;
            this.message = message;
            this.sizeFreed = sizeFreed;
        }

        public static CleanupResult success(long sizeFreed) {
            return new CleanupResult(true, "清理成功", sizeFreed);
        }

        public static CleanupResult failure(String message) {
            return new CleanupResult(false, message, 0L);
        }

        public boolean isSuccess() { return success; }
        public String getMessage() { return message; }
        public long getSizeFreed() { return sizeFreed; }
    }

    /**
     * 孤儿文件清理结果类
     */
    public static class OrphanCleanupResult {
        private final int checkedCount;
        private final int cleanedCount;
        private final long sizeFreed;

        public OrphanCleanupResult(int checkedCount, int cleanedCount, long sizeFreed) {
            this.checkedCount = checkedCount;
            this.cleanedCount = cleanedCount;
            this.sizeFreed = sizeFreed;
        }

        public int getCheckedCount() { return checkedCount; }
        public int getCleanedCount() { return cleanedCount; }
        public long getSizeFreed() { return sizeFreed; }
    }

    /**
     * 归档结果类
     */
    public static class ArchiveResult {
        private final boolean success;
        private final String message;
        private final String archivePath;

        private ArchiveResult(boolean success, String message, String archivePath) {
            this.success = success;
            this.message = message;
            this.archivePath = archivePath;
        }

        public static ArchiveResult success(String archivePath) {
            return new ArchiveResult(true, "归档成功", archivePath);
        }

        public static ArchiveResult failure(String message) {
            return new ArchiveResult(false, message, null);
        }

        public boolean isSuccess() { return success; }
        public String getMessage() { return message; }
        public String getArchivePath() { return archivePath; }
    }

    /**
     * 生命周期统计信息类
     */
    public static class LifecycleStats {
        private final int pendingCleanupCount;
        private final long pendingCleanupSize;
        private final boolean cleanupEnabled;
        private final boolean archiveEnabled;

        public LifecycleStats(int pendingCleanupCount, long pendingCleanupSize, 
                             boolean cleanupEnabled, boolean archiveEnabled) {
            this.pendingCleanupCount = pendingCleanupCount;
            this.pendingCleanupSize = pendingCleanupSize;
            this.cleanupEnabled = cleanupEnabled;
            this.archiveEnabled = archiveEnabled;
        }

        public int getPendingCleanupCount() { return pendingCleanupCount; }
        public long getPendingCleanupSize() { return pendingCleanupSize; }
        public boolean isCleanupEnabled() { return cleanupEnabled; }
        public boolean isArchiveEnabled() { return archiveEnabled; }
    }
}